package com.xjcs.saplingplan.view

import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import androidx.annotation.ColorInt
import androidx.annotation.Px
import com.xjcs.saplingplan.const.toColor
import com.xjcs.saplingplan.R
import com.xjcs.saplingplan.const.dpToPx
import kotlin.math.roundToInt

@SuppressLint("AppCompatCustomView")
class TextFontStyleGroupView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    companion object {
        private const val DEFAULT_BASE_COLOR = Color.GRAY
        private const val DEFAULT_FILL_COLOR = Color.RED
        private const val DEFAULT_TEXT_COLOR = Color.DKGRAY
        private const val DEFAULT_CIRCLE_COLOR = Color.GREEN
        private const val DEFAULT_VALUE = 0
        private const val DEFAULT_STEP_VALUE = 0
        private const val DEFAULT_MAX_VALUE = 100
        private const val DEFAULT_MIN_VALUE = 0
        private const val DEFAULT_ANIMATION_DURATION = 3000L
        private const val DEFAULT_CORNER_RADIUS_DP = 6
    }

    // 方向枚举
    enum class Direction {
        TOP_TO_BOTTOM,
        BOTTOM_TO_TOP,
        LEFT_TO_RIGHT,
        RIGHT_TO_LEFT
    }

    // 监听器接口
    interface OnRangeSeekBarChangeListener {
        fun onProgressChanged(seekBar: TextFontStyleGroupView, progress: Int, fromUser: Boolean)
        fun onStartTrackingTouch(seekBar: TextFontStyleGroupView, progress: Int)
        fun onStopTrackingTouch(seekBar: TextFontStyleGroupView, progress: Int)
    }

    // 尺寸属性
    @Px
    private var barHeight: Int = 0
    @Px
    private var circleRadius: Int = 0
    @Px
    private var circleTextSize: Int = 0
    @Px
    private var defaultPadding: Int = 0
    @Px
    private var cornerRadius: Float = 0f

    // 颜色属性
    @ColorInt
    var baseColor: Int = DEFAULT_BASE_COLOR
        set(@ColorInt color) {
            field = color
            barBasePaint.color = color
            invalidate()
        }

    @ColorInt
    var fillColor: Int = DEFAULT_FILL_COLOR
        set(@ColorInt color) {
            field = color
            barFillPaint.color = color
            invalidate()
        }

    @ColorInt
    var circleTextColor: Int = DEFAULT_TEXT_COLOR
        set(@ColorInt color) {
            field = color
            valuePaint.color = color
            invalidate()
        }

    @ColorInt
    var circleFillColor: Int = DEFAULT_CIRCLE_COLOR
        set(@ColorInt color) {
            field = color
            circlePaint.color = color
            invalidate()
        }

    @ColorInt
    var txtFillColor: Int = "#999999".toColor()
        set(@ColorInt color) {
            field = color
            textPaint.color = color
            invalidate()
        }

    // 数值属性
    var step: Int = DEFAULT_STEP_VALUE
        set(value) {
            field = value
            updateCurrentValueWithStep()
        }

    var maxValue: Int = DEFAULT_MAX_VALUE
        set(value) {
            field = value
            updateCurrentValueWithStep()
        }

    var minValue: Int = DEFAULT_MIN_VALUE
        set(value) {
            field = value
            updateCurrentValueWithStep()
        }

    var direction: Direction = Direction.LEFT_TO_RIGHT
        set(value) {
            field = value
            updateDirectionDependentValues()
        }

    var animated: Boolean = false
    var animationDuration: Long = DEFAULT_ANIMATION_DURATION

    var isTouchListenerEnabled: Boolean = true

    // 绘图工具
    private val barBasePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        style = Paint.Style.FILL
    }

    private val barFillPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        style = Paint.Style.FILL
    }

    private val circlePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        style = Paint.Style.FILL
    }

    private val valuePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        textAlign = Paint.Align.CENTER
    }

    private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        textAlign = Paint.Align.CENTER
    }

    // 动画和状态
    private var valueToDraw: Float = 0f
    private var animation: ValueAnimator? = null
    private var onRangeSeekBarChangeListener: OnRangeSeekBarChangeListener? = null

    private var _currentValue: Int = DEFAULT_VALUE
    var currentValue: Int
        get() = _currentValue
        set(value) {
            setCurrentValue(value, animated)
        }

    init {
        init(attrs)
    }

    private fun init(attrs: AttributeSet?) {
        parseAttributes(attrs)
        setupPaints()
        setupView()
        validateValues()
    }

    private fun parseAttributes(attrs: AttributeSet?) {
        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.TextFontStyleGroupView)

        try {
            step = typedArray.getInt(R.styleable.TextFontStyleGroupView_stepValue, DEFAULT_STEP_VALUE)
            minValue = typedArray.getInt(R.styleable.TextFontStyleGroupView_minValue, DEFAULT_MIN_VALUE)
            maxValue = typedArray.getInt(R.styleable.TextFontStyleGroupView_maxValue, DEFAULT_MAX_VALUE)
            _currentValue = typedArray.getInt(R.styleable.TextFontStyleGroupView_currentValue, DEFAULT_VALUE)

            barHeight = typedArray.getDimensionPixelSize(R.styleable.TextFontStyleGroupView_barHeight, 0)
            circleRadius = typedArray.getDimensionPixelSize(R.styleable.TextFontStyleGroupView_circleRadius, 0)
            circleTextSize = typedArray.getDimensionPixelSize(R.styleable.TextFontStyleGroupView_circleTextSize, 0)

            circleTextColor = typedArray.getColor(R.styleable.TextFontStyleGroupView_circleTextColor, DEFAULT_TEXT_COLOR)
            circleFillColor = typedArray.getColor(R.styleable.TextFontStyleGroupView_circleFillColor, DEFAULT_CIRCLE_COLOR)
            baseColor = typedArray.getColor(R.styleable.TextFontStyleGroupView_baseColor, DEFAULT_BASE_COLOR)
            fillColor = typedArray.getColor(R.styleable.TextFontStyleGroupView_fillColor, DEFAULT_FILL_COLOR)

            val orientationIndex = typedArray.getInt(R.styleable.TextFontStyleGroupView_orientation, 0)
            direction = Direction.values().getOrElse(orientationIndex) { Direction.LEFT_TO_RIGHT }

        } finally {
            typedArray.recycle()
        }

        defaultPadding = circleRadius
        cornerRadius = DEFAULT_CORNER_RADIUS_DP.dpToPx(context).toFloat()
        setPadding(defaultPadding, 0, defaultPadding, 0)
    }

    private fun setupPaints() {
        barBasePaint.color = baseColor
        barFillPaint.color = fillColor
        valuePaint.apply {
            textSize = circleTextSize.toFloat()
            color = circleTextColor
        }
        circlePaint.color = circleFillColor
        textPaint.color = txtFillColor
    }

    private fun setupView() {
        isSaveEnabled = true
        setBackgroundColor(Color.TRANSPARENT)
    }

    private fun validateValues() {
        require(minValue <= maxValue) { "minValue must be less than or equal to maxValue" }
        require(_currentValue in minValue..maxValue) { "currentValue must be between minValue and maxValue" }
    }

    private fun updateDirectionDependentValues() {
        if (direction == Direction.BOTTOM_TO_TOP || direction == Direction.RIGHT_TO_LEFT) {
            val temp = maxValue
            maxValue = minValue
            minValue = temp
        }
    }

    private fun updateCurrentValueWithStep() {
        if (step > 0) {
            _currentValue = (_currentValue / step) * step
        }
        invalidate()
        requestLayout()
    }

    fun setCurrentValue(value: Int, animate: Boolean) {
        val clampedValue = value.coerceIn(minValue, maxValue)
        val steppedValue = if (step > 0) (clampedValue / step) * step else clampedValue

        if (steppedValue == _currentValue) return

        val previousValue = _currentValue
        _currentValue = steppedValue

        animation?.cancel()

        if (animate) {
            animateValueChange(previousValue, steppedValue)
        } else {
            valueToDraw = steppedValue.toFloat()
            onRangeSeekBarChangeListener?.onProgressChanged(this, steppedValue, false)
            invalidate()
        }
    }

    private fun animateValueChange(from: Int, to: Int) {
        animation = ValueAnimator.ofFloat(from.toFloat(), to.toFloat()).apply {
            val changeInValue = kotlin.math.abs(to - from)
            val progressRatio = changeInValue.toFloat() / (maxValue - minValue).toFloat()
            duration = (animationDuration * progressRatio).toLong()

            addUpdateListener { animator ->
                valueToDraw = animator.animatedValue as Float
                onRangeSeekBarChangeListener?.onProgressChanged(
                    this@TextFontStyleGroupView,
                    valueToDraw.toInt(),
                    false
                )
                invalidate()
            }
            start()
        }
    }

    fun setOnRangeSeekBarChangeListener(listener: OnRangeSeekBarChangeListener?) {
        onRangeSeekBarChangeListener = listener
    }

    // 测量和绘制
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val width = measureDimension(widthMeasureSpec, true)
        val height = measureDimension(heightMeasureSpec, false)
        setMeasuredDimension(width, height)
    }

    private fun measureDimension(measureSpec: Int, isWidth: Boolean): Int {
        val mode = MeasureSpec.getMode(measureSpec)
        val size = MeasureSpec.getSize(measureSpec)

        return when (mode) {
            MeasureSpec.EXACTLY -> size
            MeasureSpec.AT_MOST -> {
                val minSize = if (isWidth) {
                    paddingLeft + paddingRight + suggestedMinimumWidth
                } else {
                    paddingTop + paddingBottom + suggestedMinimumHeight
                }
                minSize.coerceAtMost(size)
            }
            else -> { // UNSPECIFIED
                if (isWidth) {
                    paddingLeft + paddingRight + suggestedMinimumWidth
                } else {
                    paddingTop + paddingBottom + suggestedMinimumHeight
                }
            }
        }
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        when (direction) {
            Direction.TOP_TO_BOTTOM, Direction.BOTTOM_TO_TOP -> drawVerticalBar(canvas)
            Direction.LEFT_TO_RIGHT, Direction.RIGHT_TO_LEFT -> drawHorizontalBar(canvas)
        }
    }

    private fun drawVerticalBar(canvas: Canvas) {
        val barLength = (height - paddingTop - paddingBottom).toFloat()
        val barCenterX = width / 2f
        val halfBarHeight = barHeight / 2f

        val rect = RectF(
            barCenterX - halfBarHeight,
            paddingTop.toFloat(),
            barCenterX + halfBarHeight,
            paddingTop + barLength
        )

        canvas.drawRoundRect(rect, cornerRadius, cornerRadius, barBasePaint)
        drawVerticalFill(canvas, rect, barCenterX)
    }

    private fun drawVerticalFill(canvas: Canvas, baseRect: RectF, barCenterX: Float) {
        val progress = calculateProgress(valueToDraw.toInt(), minValue, maxValue)
        val fillLength = baseRect.height() * progress / 100f

        val fillRect = when (direction) {
            Direction.TOP_TO_BOTTOM -> RectF(
                baseRect.left,
                baseRect.top,
                baseRect.right,
                baseRect.top + fillLength
            )
            Direction.BOTTOM_TO_TOP -> RectF(
                baseRect.left,
                baseRect.bottom - fillLength,
                baseRect.right,
                baseRect.bottom
            )
            else -> throw IllegalStateException("Invalid direction for vertical bar")
        }

        canvas.drawRoundRect(fillRect, cornerRadius, cornerRadius, barFillPaint)
        drawThumb(canvas, barCenterX, fillRect, true)
    }

    private fun drawHorizontalBar(canvas: Canvas) {
        val barLength = (width - paddingLeft - paddingRight).toFloat()
        val barCenterY = height / 2f
        val halfBarHeight = barHeight / 2f

        val rect = RectF(
            paddingLeft.toFloat(),
            barCenterY - halfBarHeight,
            paddingLeft + barLength,
            barCenterY + halfBarHeight
        )

        canvas.drawRoundRect(rect, cornerRadius, cornerRadius, barBasePaint)
        drawHorizontalFill(canvas, rect, barCenterY)
    }

    private fun drawHorizontalFill(canvas: Canvas, baseRect: RectF, barCenterY: Float) {
        val progress = calculateProgress(valueToDraw.toInt(), minValue, maxValue)
        val fillLength = baseRect.width() * progress / 100f

        val fillRect = when (direction) {
            Direction.LEFT_TO_RIGHT -> RectF(
                baseRect.left,
                baseRect.top,
                baseRect.left + fillLength,
                baseRect.bottom
            )
            Direction.RIGHT_TO_LEFT -> RectF(
                baseRect.right - fillLength,
                baseRect.top,
                baseRect.right,
                baseRect.bottom
            )
            else -> throw IllegalStateException("Invalid direction for horizontal bar")
        }

        canvas.drawRoundRect(fillRect, cornerRadius, cornerRadius, barFillPaint)
        drawThumb(canvas, barCenterY, fillRect, false)
    }

    private fun drawThumb(canvas: Canvas, center: Float, fillRect: RectF, isVertical: Boolean) {
        val thumbPosition = if (isVertical) {
            when (direction) {
                Direction.TOP_TO_BOTTOM -> fillRect.bottom
                Direction.BOTTOM_TO_TOP -> fillRect.top
                else -> center
            }
        } else {
            when (direction) {
                Direction.LEFT_TO_RIGHT -> fillRect.right
                Direction.RIGHT_TO_LEFT -> fillRect.left
                else -> center
            }
        }

        val thumbRect = if (isVertical) {
            RectF(
                center - circleRadius,
                thumbPosition - circleRadius,
                center + circleRadius,
                thumbPosition + circleRadius
            )
        } else {
            RectF(
                thumbPosition - circleRadius,
                center - circleRadius,
                thumbPosition + circleRadius,
                center + circleRadius
            )
        }

        canvas.drawRoundRect(thumbRect, cornerRadius, cornerRadius, circlePaint)
        drawValueText(canvas, thumbRect.centerX(), thumbRect.centerY())
    }

    private fun drawValueText(canvas: Canvas, x: Float, y: Float) {
        val valueString = valueToDraw.roundToInt().toString()
        val bounds = Rect()
        valuePaint.getTextBounds(valueString, 0, valueString.length, bounds)
        canvas.drawText(valueString, x, y + bounds.height() / 2f, valuePaint)
    }

    private fun calculateProgress(value: Int, min: Int, max: Int): Int {
        return if (max == min) 0 else 100 * (value - min) / (max - min)
    }

    // 触摸事件处理
    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent): Boolean {
        if (!isTouchListenerEnabled || !isEnabled) {
            return false
        }

        val (coordinate, canvasSize) = getTouchCoordinates(event)
        val normalizedCoordinate = coordinate.coerceIn(0f, canvasSize)

        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                onRangeSeekBarChangeListener?.onStartTrackingTouch(this, currentValue)
                updateValueFromCoordinate(normalizedCoordinate, canvasSize)
                parent?.requestDisallowInterceptTouchEvent(true)
            }
            MotionEvent.ACTION_MOVE -> {
                updateValueFromCoordinate(normalizedCoordinate, canvasSize)
            }
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                updateValueFromCoordinate(normalizedCoordinate, canvasSize)
                onRangeSeekBarChangeListener?.onStopTrackingTouch(this, currentValue)
                parent?.requestDisallowInterceptTouchEvent(false)
            }
        }

        performClick()
        return true
    }

    override fun performClick(): Boolean {
        super.performClick()
        return true
    }

    private fun getTouchCoordinates(event: MotionEvent): Pair<Float, Float> {
        return when (direction) {
            Direction.TOP_TO_BOTTOM, Direction.BOTTOM_TO_TOP -> {
                event.y to (height - paddingTop - paddingBottom).toFloat()
            }
            Direction.LEFT_TO_RIGHT, Direction.RIGHT_TO_LEFT -> {
                event.x to (width - paddingLeft - paddingRight).toFloat()
            }
        }
    }

    private fun updateValueFromCoordinate(coordinate: Float, canvasSize: Float) {
        val progress = (coordinate / canvasSize * 100).toInt().coerceIn(0, 100)
        val value = minValue + (progress * (maxValue - minValue)) / 100
        setCurrentValue(value, false)
        onRangeSeekBarChangeListener?.onProgressChanged(this, currentValue, true)
    }
}